﻿// -------------------------------------------------------------------------
//    @FileName         :    BagPageTest.cpp
//    @Author           :    gaoyi
//    @Date             :    2025/1/20
//    @Email            :    445267987@qq.com
//    @Module           :    BagPageTest
//
// -------------------------------------------------------------------------

#include "BagSystemTestBase.h"
#include "MockItemDesc.h"

/**
 * @brief 背包页面测试类
 * 
 * 测试背包页面的基础功能：
 * - 背包初始化和状态管理
 * - 物品添加、删除、查找
 * - 背包容量管理
 * - 物品排序和整理
 * - 背包页面数据同步
 */
class BagPageTest : public BagSystemTestBase {
protected:
    void SetUp() override {
        BagSystemTestBase::SetUp();
        
        // 创建测试用背包页面
        m_bagPage = CreateTestBagPage(TEST_BAG_TYPE_NORMAL, 50);
        m_equipBagPage = CreateTestBagPage(TEST_BAG_TYPE_EQUIP, 30);
        m_materialBagPage = CreateTestBagPage(TEST_BAG_TYPE_MATERIAL, 100);
    }
    
    void TearDown() override {
        m_bagPage = nullptr;
        m_equipBagPage = nullptr;
        m_materialBagPage = nullptr;
        
        BagSystemTestBase::TearDown();
    }

protected:
    NFBagPage* m_bagPage;
    NFBagPage* m_equipBagPage;
    NFBagPage* m_materialBagPage;
};

// === 基础功能测试 ===

/**
 * @brief 测试背包初始化
 */
TEST_F(BagPageTest, InitializationTest) {
    ASSERT_NE(m_bagPage, nullptr) << "背包页面创建失败";
    ASSERT_NE(m_equipBagPage, nullptr) << "装备背包页面创建失败";
    ASSERT_NE(m_materialBagPage, nullptr) << "材料背包页面创建失败";
    
    // 验证背包初始状态
    ASSERT_EQ(m_bagPage->GetMaxGrid(), 50) << "普通背包最大格子数不正确";
    ASSERT_EQ(m_equipBagPage->GetMaxGrid(), 30) << "装备背包最大格子数不正确";
    ASSERT_EQ(m_materialBagPage->GetMaxGrid(), 100) << "材料背包最大格子数不正确";
    
    // 验证背包为空
    ASSERT_BAG_USED_COUNT(m_bagPage, 0);
    ASSERT_BAG_EMPTY_COUNT(m_bagPage, 50);
    ASSERT_BAG_USED_COUNT(m_equipBagPage, 0);
    ASSERT_BAG_EMPTY_COUNT(m_equipBagPage, 30);
    ASSERT_BAG_USED_COUNT(m_materialBagPage, 0);
    ASSERT_BAG_EMPTY_COUNT(m_materialBagPage, 100);
}

/**
 * @brief 测试单个物品添加
 */
TEST_F(BagPageTest, AddSingleItemTest) {
    // 创建测试物品
    NFGridItem item = CreateTestItem(TestItemIds::NORMAL_ITEM_1, 1);
    
    // 添加物品到背包
    int result = m_bagPage->AddItem(item);
    ASSERT_EQ(result, 0) << "添加物品失败";
    
    // 验证背包状态
    ASSERT_BAG_USED_COUNT(m_bagPage, 1);
    ASSERT_BAG_EMPTY_COUNT(m_bagPage, 49);
    
    // 验证物品是否正确添加
    ASSERT_BAG_ITEM_COUNT(m_bagPage, TestItemIds::NORMAL_ITEM_1, 1);
    
    // 验证物品在正确的位置
    const NFGridItem* bagItem = m_bagPage->GetItem(0);
    ASSERT_NE(bagItem, nullptr) << "获取物品失败";
    VerifyItemProperties(*bagItem, TestItemIds::NORMAL_ITEM_1, 1, 1);
}

/**
 * @brief 测试多个物品添加
 */
TEST_F(BagPageTest, AddMultipleItemsTest) {
    // 添加多个不同的物品
    std::vector<int> itemIds = {
        TestItemIds::NORMAL_ITEM_1,
        TestItemIds::NORMAL_ITEM_2,
        TestItemIds::NORMAL_ITEM_3,
        TestItemIds::WEAPON_SWORD,
        TestItemIds::POTION_HP
    };
    
    for (size_t i = 0; i < itemIds.size(); ++i) {
        NFGridItem item = CreateTestItem(itemIds[i], 1);
        int result = m_bagPage->AddItem(item);
        ASSERT_EQ(result, 0) << "添加物品失败: " << itemIds[i];
    }
    
    // 验证背包状态
    ASSERT_BAG_USED_COUNT(m_bagPage, itemIds.size());
    ASSERT_BAG_EMPTY_COUNT(m_bagPage, 50 - itemIds.size());
    
    // 验证每个物品都正确添加
    for (int itemId : itemIds) {
        ASSERT_BAG_ITEM_COUNT(m_bagPage, itemId, 1);
    }
}

/**
 * @brief 测试可堆叠物品添加
 */
TEST_F(BagPageTest, AddStackableItemsTest) {
    // 添加可堆叠物品
    NFGridItem item1 = CreateTestItem(TestItemIds::STACKABLE_ARROW, 50);
    NFGridItem item2 = CreateTestItem(TestItemIds::STACKABLE_ARROW, 30);
    
    int result1 = m_bagPage->AddItem(item1);
    ASSERT_EQ(result1, 0) << "添加第一个可堆叠物品失败";
    
    int result2 = m_bagPage->AddItem(item2);
    ASSERT_EQ(result2, 0) << "添加第二个可堆叠物品失败";
    
    // 验证物品是否正确堆叠
    ASSERT_BAG_ITEM_COUNT(m_bagPage, TestItemIds::STACKABLE_ARROW, 80);
    ASSERT_BAG_USED_COUNT(m_bagPage, 1); // 应该只占用一个格子
}

/**
 * @brief 测试物品删除
 */
TEST_F(BagPageTest, RemoveItemTest) {
    // 先添加一些物品
    NFGridItem item1 = CreateTestItem(TestItemIds::NORMAL_ITEM_1, 1);
    NFGridItem item2 = CreateTestItem(TestItemIds::NORMAL_ITEM_2, 1);
    NFGridItem item3 = CreateTestItem(TestItemIds::STACKABLE_ARROW, 100);
    
    m_bagPage->AddItem(item1);
    m_bagPage->AddItem(item2);
    m_bagPage->AddItem(item3);
    
    // 验证添加成功
    ASSERT_BAG_USED_COUNT(m_bagPage, 3);
    
    // 删除单个物品
    int result = m_bagPage->RemoveItem(0);
    ASSERT_EQ(result, 0) << "删除物品失败";
    
    // 验证删除结果
    ASSERT_BAG_USED_COUNT(m_bagPage, 2);
    ASSERT_BAG_ITEM_COUNT(m_bagPage, TestItemIds::NORMAL_ITEM_1, 0);
    
    // 部分删除堆叠物品
    const NFGridItem* stackItem = m_bagPage->FindItem(TestItemIds::STACKABLE_ARROW);
    ASSERT_NE(stackItem, nullptr) << "找不到可堆叠物品";
    
    int gridIndex = stackItem->GetGridIndex();
    int partialResult = m_bagPage->RemoveItemByCount(gridIndex, 50);
    ASSERT_EQ(partialResult, 0) << "部分删除可堆叠物品失败";
    
    // 验证部分删除结果
    ASSERT_BAG_ITEM_COUNT(m_bagPage, TestItemIds::STACKABLE_ARROW, 50);
    ASSERT_BAG_USED_COUNT(m_bagPage, 2); // 格子数不变
}

/**
 * @brief 测试物品查找
 */
TEST_F(BagPageTest, FindItemTest) {
    // 添加测试物品
    NFGridItem item1 = CreateTestItem(TestItemIds::NORMAL_ITEM_1, 1);
    NFGridItem item2 = CreateTestItem(TestItemIds::WEAPON_SWORD, 1);
    NFGridItem item3 = CreateTestItem(TestItemIds::STACKABLE_ARROW, 100);
    
    m_bagPage->AddItem(item1);
    m_bagPage->AddItem(item2);
    m_bagPage->AddItem(item3);
    
    // 按物品ID查找
    const NFGridItem* foundItem1 = m_bagPage->FindItem(TestItemIds::NORMAL_ITEM_1);
    ASSERT_NE(foundItem1, nullptr) << "按ID查找物品失败";
    VerifyItemProperties(*foundItem1, TestItemIds::NORMAL_ITEM_1, 1, 1);
    
    const NFGridItem* foundItem2 = m_bagPage->FindItem(TestItemIds::WEAPON_SWORD);
    ASSERT_NE(foundItem2, nullptr) << "按ID查找装备失败";
    VerifyItemProperties(*foundItem2, TestItemIds::WEAPON_SWORD, 1, 1);
    
    const NFGridItem* foundItem3 = m_bagPage->FindItem(TestItemIds::STACKABLE_ARROW);
    ASSERT_NE(foundItem3, nullptr) << "按ID查找可堆叠物品失败";
    VerifyItemProperties(*foundItem3, TestItemIds::STACKABLE_ARROW, 100, 1);
    
    // 查找不存在的物品
    const NFGridItem* notFoundItem = m_bagPage->FindItem(99999);
    ASSERT_EQ(notFoundItem, nullptr) << "查找不存在的物品应该返回nullptr";
}

/**
 * @brief 测试按UUID查找物品
 */
TEST_F(BagPageTest, FindItemByUUIDTest) {
    // 创建带UUID的物品
    NFGridItem item1 = CreateTestItem(TestItemIds::WEAPON_SWORD, 1);
    NFGridItem item2 = CreateTestItem(TestItemIds::ARMOR_HELMET, 1);
    
    uint64_t uuid1 = item1.GetUUID();
    uint64_t uuid2 = item2.GetUUID();
    
    m_bagPage->AddItem(item1);
    m_bagPage->AddItem(item2);
    
    // 按UUID查找
    const NFGridItem* foundItem1 = m_bagPage->FindItemByUUID(uuid1);
    ASSERT_NE(foundItem1, nullptr) << "按UUID查找物品失败";
    ASSERT_EQ(foundItem1->GetUUID(), uuid1) << "找到的物品UUID不匹配";
    
    const NFGridItem* foundItem2 = m_bagPage->FindItemByUUID(uuid2);
    ASSERT_NE(foundItem2, nullptr) << "按UUID查找物品失败";
    ASSERT_EQ(foundItem2->GetUUID(), uuid2) << "找到的物品UUID不匹配";
    
    // 查找不存在的UUID
    const NFGridItem* notFoundItem = m_bagPage->FindItemByUUID(99999);
    ASSERT_EQ(notFoundItem, nullptr) << "查找不存在的UUID应该返回nullptr";
}

/**
 * @brief 测试背包容量限制
 */
TEST_F(BagPageTest, CapacityLimitTest) {
    // 创建一个小容量的背包进行测试
    NFBagPage* smallBag = CreateTestBagPage(TEST_BAG_TYPE_NORMAL, 3);
    
    // 添加物品直到满
    for (int i = 0; i < 3; ++i) {
        NFGridItem item = CreateTestItem(TestItemIds::NORMAL_ITEM_1 + i, 1);
        int result = smallBag->AddItem(item);
        ASSERT_EQ(result, 0) << "添加物品到未满背包失败";
    }
    
    // 验证背包已满
    ASSERT_BAG_USED_COUNT(smallBag, 3);
    ASSERT_BAG_EMPTY_COUNT(smallBag, 0);
    
    // 尝试添加更多物品应该失败
    NFGridItem extraItem = CreateTestItem(TestItemIds::NORMAL_ITEM_1 + 10, 1);
    int result = smallBag->AddItem(extraItem);
    ASSERT_NE(result, 0) << "向满背包添加物品应该失败";
    
    // 验证背包状态没有改变
    ASSERT_BAG_USED_COUNT(smallBag, 3);
    ASSERT_BAG_EMPTY_COUNT(smallBag, 0);
}

/**
 * @brief 测试背包整理功能
 */
TEST_F(BagPageTest, SortAndOrganizeTest) {
    // 添加不同类型的物品
    std::vector<std::pair<int, int>> items = {
        {TestItemIds::MATERIAL_WOOD, 50},
        {TestItemIds::WEAPON_SWORD, 1},
        {TestItemIds::POTION_HP, 10},
        {TestItemIds::MATERIAL_STONE, 30},
        {TestItemIds::ARMOR_HELMET, 1},
        {TestItemIds::POTION_MP, 20}
    };
    
    // 随机顺序添加物品
    for (const auto& itemPair : items) {
        NFGridItem item = CreateTestItem(itemPair.first, itemPair.second);
        m_bagPage->AddItem(item);
    }
    
    // 验证物品都已添加
    ASSERT_BAG_USED_COUNT(m_bagPage, items.size());
    
    // 执行背包整理
    int sortResult = m_bagPage->SortItems();
    ASSERT_EQ(sortResult, 0) << "背包整理失败";
    
    // 验证物品数量没有变化
    ASSERT_BAG_USED_COUNT(m_bagPage, items.size());
    for (const auto& itemPair : items) {
        ASSERT_BAG_ITEM_COUNT(m_bagPage, itemPair.first, itemPair.second);
    }
}

/**
 * @brief 测试背包物品移动
 */
TEST_F(BagPageTest, MoveItemTest) {
    // 添加测试物品
    NFGridItem item1 = CreateTestItem(TestItemIds::NORMAL_ITEM_1, 1);
    NFGridItem item2 = CreateTestItem(TestItemIds::NORMAL_ITEM_2, 1);
    NFGridItem item3 = CreateTestItem(TestItemIds::NORMAL_ITEM_3, 1);
    
    m_bagPage->AddItem(item1);
    m_bagPage->AddItem(item2);
    m_bagPage->AddItem(item3);
    
    // 验证初始位置
    const NFGridItem* itemAt0 = m_bagPage->GetItem(0);
    const NFGridItem* itemAt1 = m_bagPage->GetItem(1);
    const NFGridItem* itemAt2 = m_bagPage->GetItem(2);
    
    ASSERT_NE(itemAt0, nullptr);
    ASSERT_NE(itemAt1, nullptr);
    ASSERT_NE(itemAt2, nullptr);
    
    int originalId0 = itemAt0->GetItemID();
    int originalId1 = itemAt1->GetItemID();
    
    // 移动物品：将位置0的物品移动到位置1
    int moveResult = m_bagPage->MoveItem(0, 1);
    ASSERT_EQ(moveResult, 0) << "移动物品失败";
    
    // 验证移动结果
    const NFGridItem* newItemAt0 = m_bagPage->GetItem(0);
    const NFGridItem* newItemAt1 = m_bagPage->GetItem(1);
    
    ASSERT_NE(newItemAt0, nullptr);
    ASSERT_NE(newItemAt1, nullptr);
    
    // 物品应该交换位置
    ASSERT_EQ(newItemAt0->GetItemID(), originalId1) << "位置0的物品ID不正确";
    ASSERT_EQ(newItemAt1->GetItemID(), originalId0) << "位置1的物品ID不正确";
    
    // 总物品数量应该不变
    ASSERT_BAG_USED_COUNT(m_bagPage, 3);
}

/**
 * @brief 测试背包数据序列化
 */
TEST_F(BagPageTest, SerializationTest) {
    // 添加多种类型的物品
    NFGridItem item1 = CreateTestItem(TestItemIds::NORMAL_ITEM_1, 1);
    NFGridItem item2 = CreateTestItem(TestItemIds::WEAPON_SWORD, 1);
    NFGridItem item3 = CreateTestItem(TestItemIds::STACKABLE_ARROW, 100);
    
    m_bagPage->AddItem(item1);
    m_bagPage->AddItem(item2);
    m_bagPage->AddItem(item3);
    
    // 序列化背包数据
    std::string serializedData;
    int serializeResult = m_bagPage->SerializeToPB(serializedData);
    ASSERT_EQ(serializeResult, 0) << "序列化背包数据失败";
    ASSERT_FALSE(serializedData.empty()) << "序列化数据为空";
    
    // 创建新的背包并反序列化
    NFBagPage* newBag = CreateTestBagPage(TEST_BAG_TYPE_NORMAL, 50);
    int deserializeResult = newBag->DeserializeFromPB(serializedData);
    ASSERT_EQ(deserializeResult, 0) << "反序列化背包数据失败";
    
    // 验证反序列化结果
    ASSERT_BAG_USED_COUNT(newBag, 3);
    ASSERT_BAG_ITEM_COUNT(newBag, TestItemIds::NORMAL_ITEM_1, 1);
    ASSERT_BAG_ITEM_COUNT(newBag, TestItemIds::WEAPON_SWORD, 1);
    ASSERT_BAG_ITEM_COUNT(newBag, TestItemIds::STACKABLE_ARROW, 100);
}

/**
 * @brief 测试背包状态查询
 */
TEST_F(BagPageTest, StatusQueryTest) {
    // 初始状态查询
    ASSERT_TRUE(m_bagPage->IsEmpty()) << "新背包应该为空";
    ASSERT_FALSE(m_bagPage->IsFull()) << "新背包不应该满";
    ASSERT_EQ(m_bagPage->GetUsedGridCount(), 0) << "使用格子数应该为0";
    ASSERT_EQ(m_bagPage->GetEmptyGridCount(), 50) << "空闲格子数应该为50";
    
    // 添加一些物品
    for (int i = 0; i < 10; ++i) {
        NFGridItem item = CreateTestItem(TestItemIds::NORMAL_ITEM_1 + i, 1);
        m_bagPage->AddItem(item);
    }
    
    // 部分填充状态查询
    ASSERT_FALSE(m_bagPage->IsEmpty()) << "有物品的背包不应该为空";
    ASSERT_FALSE(m_bagPage->IsFull()) << "部分填充的背包不应该满";
    ASSERT_EQ(m_bagPage->GetUsedGridCount(), 10) << "使用格子数应该为10";
    ASSERT_EQ(m_bagPage->GetEmptyGridCount(), 40) << "空闲格子数应该为40";
    
    // 填满背包
    for (int i = 10; i < 50; ++i) {
        NFGridItem item = CreateTestItem(TestItemIds::NORMAL_ITEM_1 + i, 1);
        m_bagPage->AddItem(item);
    }
    
    // 满背包状态查询
    ASSERT_FALSE(m_bagPage->IsEmpty()) << "满背包不应该为空";
    ASSERT_TRUE(m_bagPage->IsFull()) << "满背包应该为满";
    ASSERT_EQ(m_bagPage->GetUsedGridCount(), 50) << "使用格子数应该为50";
    ASSERT_EQ(m_bagPage->GetEmptyGridCount(), 0) << "空闲格子数应该为0";
}

/**
 * @brief 测试背包清空功能
 */
TEST_F(BagPageTest, ClearBagTest) {
    // 添加多个物品
    for (int i = 0; i < 10; ++i) {
        NFGridItem item = CreateTestItem(TestItemIds::NORMAL_ITEM_1 + i, GetRandomCount(1, 10));
        m_bagPage->AddItem(item);
    }
    
    // 验证背包有物品
    ASSERT_BAG_USED_COUNT(m_bagPage, 10);
    ASSERT_FALSE(m_bagPage->IsEmpty()) << "背包应该不为空";
    
    // 清空背包
    int clearResult = m_bagPage->Clear();
    ASSERT_EQ(clearResult, 0) << "清空背包失败";
    
    // 验证背包已清空
    ASSERT_BAG_USED_COUNT(m_bagPage, 0);
    ASSERT_BAG_EMPTY_COUNT(m_bagPage, 50);
    ASSERT_TRUE(m_bagPage->IsEmpty()) << "清空后背包应该为空";
    
    // 验证所有格子都为空
    for (int i = 0; i < m_bagPage->GetMaxGrid(); ++i) {
        const NFGridItem* item = m_bagPage->GetItem(i);
        ASSERT_TRUE(item == nullptr || item->IsEmpty()) << "格子" << i << "应该为空";
    }
} 